<?php

namespace App\Services\Game;

use App\DTOS\Admin\PayOrderInsertDTO;
use App\DTOS\DouyinCreateOrderDTO;
use App\DTOS\NeiGouDTO;
use App\Exceptions\ServiceException;
use App\Models\Customer;
use App\Models\Game\GameGoods;
use App\Models\Game\PayOrder;
use App\Models\Game\Server;
use App\Services\RestClientService;
use App\Utils\MyLog;
use App\Utils\ResponseUtil;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

class DouyinService
{
    private $appId = "343460";
    private $secretKey = "nabys4rRhHlej3xL7lcPGIZ5c3KKJjsT";
    private $host = "https://usdk.dailygn.com";


    private NeigouService $NeigouService;
    private PayOrderService $payOrderService;
    private RestClientService $restClientService;

    /**
     * DouyinService constructor.
     * @param NeigouService $NeigouService
     */
    public function __construct(NeigouService $NeigouService,PayOrderService $payOrderService,RestClientService $restClientService)
    {
        $this->NeigouService = $NeigouService;
        $this->payOrderService = $payOrderService;
        $this->restClientService = $restClientService;
    }


    /**
     * @param string $accessToken
     * @return array
     * @throws \Exception
     */
    public function login($accessToken){

        $url = $this->host . "/gsdk/usdk/account/verify_user";
        $body = [
            'ts'=>time(),
            'app_id'=>$this->appId,
            'access_token'=>$accessToken,
        ];

        $body['sign'] = $this->getSign($body,$this->secretKey);

        $responseDataJsonString = httpPost($url,dataToParamsAndEncoded($body),['Content-Type: application/x-www-form-urlencoded']);

        $responseData = json_decode($responseDataJsonString,true);

        $code = data_get($responseData,'code');

        if($code != 0){
            Log::error("douyin verify " . json_encode($responseData));
            throw new \Exception($responseData['message'],-1);
        }

        return $responseData['data'];
    }


    /** 获取抖音签名
     * @param array $data
     * @param $secretKey
     * @return string
     * @throws string
     */
    public function getSign($data,$secretKey){
        if (!$secretKey) return false;
        unset($data['client_ip']);
        unset($data['sign']);
        ksort($data);
        $sha1Binary = hash_hmac('sha1',dataToParams($data),$secretKey,true);
        return base64_encode($sha1Binary);  //结果B
    }

    /**
     * @param DouyinCreateOrderDTO $DTO
     * @return array [sdkParam,orderNo]
     * @throws ServiceException
     */
    public function createOrder(DouyinCreateOrderDTO $DTO){
        $orderNo = 'dy_'. getSnowFlakeId();
        $url = $this->host . '/gsdk/usdk/payment/live_pre_order';
        $goodsId = $DTO->getGoodsId();
        $serverId = $DTO->getServerId();
        $number = $DTO->getNumber();
        $riskControlInfo = $DTO->getRiskControlInfo();
        $clientIp = $DTO->getClientIp();
        $priceFee = $DTO->getPriceFee(); //前端传入的参数
        $roleId = $DTO->getRoleId();
        $customerId = $DTO->getCustomerId();
        $customer = Customer::query()->find($customerId);
        if(!$customer){
            throw new ServiceException('客户不存在',-1);
        }
        $sdkOpenId = $customer->channel_uuid;
        if(!$sdkOpenId){
            throw new ServiceException('非抖音用户',-1);
        }

        //记录到订单表 begin

        $gameGoods = GameGoods::query()->where('id',$goodsId)->first();

        $payOrderInertDTO = new PayOrderInsertDTO();

        $payOrderInertDTO->setOrderNo($orderNo);
        $payOrderInertDTO->setName($gameGoods->name);
        $payOrderInertDTO->setDetail($gameGoods->detail);
        $payOrderInertDTO->setStatus(0);
        $payOrderInertDTO->setGameArea($serverId);
        $payOrderInertDTO->setFrontFee($priceFee);
        $payOrderInertDTO->setFee($gameGoods->price_fee);
        $payOrderInertDTO->setRoleId($roleId);
        $payOrderInertDTO->setGoodsId($goodsId);
        $payOrderInertDTO->setNumber($number);
        $payOrderInertDTO->setCreatedAt(now()->format("Y-m-d H:i:s"));
        $payOrderInertDTO->setCustomerId($customerId);
        $this->payOrderService->createOrder($payOrderInertDTO);
        //记录到订单表 end

        if (!$gameGoods) {
            throw new \Exception('此商品不存在',-1);
        }
        $server = Server::query()->where('server_id',$serverId)->first();
        if (!$server){
            throw new \Exception('此服务器不存在',-1);
        }
        $status = data_get($server,'status');
        if ($status!=1){ //未开服
            throw new \Exception('当前服务器未开服',-1);
        }
        if ($gameGoods->price_fee % 10 !=0 ){
            throw new \Exception('金额需必须是10的整数');
        }
        $body = [ //http body
            'aid'=>$this->appId,
            'cp_order_id'=>$orderNo,
            'product_id'=>$gameGoods->id,
            'product_name'=>$gameGoods->name,
            'product_desc'=>$gameGoods->detail,
            'product_amount'=>$gameGoods->price_fee * $number,
            'actual_amount'=>$gameGoods->price_fee * $number,
            'sdk_open_id'=>$sdkOpenId,
            'client_ip'=>$clientIp,
            'callback_url'=>'http://api.hx160.com/douyin/payCallback',
            'risk_control_info'=>json_encode(json_decode($riskControlInfo,true)),
            'trade_type'=>2,
        ];

        $body['sign'] = $this->getSign($body,$this->secretKey);

        //Log::info("douyin create order , body: " . json_encode($body)); //1

        $responseDataJsonString = httpPost($url,dataToParamsAndEncoded($body),['Content-Type: application/x-www-form-urlencoded']);

        //Log::info("douyin create order ,response: " . $responseDataJsonString);

        $responseData = json_decode($responseDataJsonString,true);

        $code = data_get($responseData,'code');

        if($code==0){
            return [
                'orderNo'=>$orderNo,
                'sdkParam'=>data_get($responseData,'sdk_param')
            ];
        }
        switch($code){
            case -1001: throw new \Exception('参数异常',$code);
            case -2022: throw new \Exception('未实名用户不能支付',$code);
            case -2023: throw new \Exception('国内未成年人充值限额(未满8岁)',$code);
            case -2025: throw new \Exception('国内未成年单次充值限制',$code);
            case -2026: throw new \Exception('国内未成年人月充值限制',$code);
            case -2027: throw new \Exception('国内未成年月充值已达上限',$code);
            case -4001: throw new \Exception('被风控拦截（CP需要弹框显示错误信息）',$code);
            case -4002: throw new \Exception('操作频繁（CP需要弹框显示错误信息）',$code);
            case -5000: throw new \Exception('系统错误',$code);
        }
        throw new \Exception('其他未知错误',$code);
    }

    /**
     * @param PayOrder $payOrder
     * @return bool #是否支付
     * @throws ServiceException
     */
    public function query(PayOrder $payOrder){ //抖音订单主动查询
        $requestData = [
            'app_id'=>$this->appId,
            'cp_order_id'=>$payOrder->order_no,
        ];
        $requestData['sign'] = $this->getSign($requestData,$this->secretKey);
        $url = "https://usdk.dailygn.com/gsdk/usdk/payment/order/query?" . dataToParamsAndEncoded($requestData);
        $result = file_get_contents($url); //GET查询
     /*   MyLog::info("订单查询: {$payOrder->order_no}");
        MyLog::info("订单查询result: " . $result );*/
        $responseData = json_decode($result,true);
        $code = data_get($responseData,'code');
        $dyOrderstatusPayTime = data_get($responseData,'data.pay_time');
        $dyOrderstatus = data_get($responseData,'data.status');
        if($code == 0){ //;响应成功
            if ($dyOrderstatusPayTime > 0 && $dyOrderstatus==2){
                if ($payOrder->status !=1 ) {
                    $payOrder->updated_at = date("Y-m-d H:i:s");
                    $payOrder->status = 1;
                    $payOrder->save();

                    $goodsId = data_get($payOrder,'goods_id');
                    $gameGoods = GameGoods::query()->find($goodsId);
                    $typeValue = data_get($gameGoods,'type_value');

                    $neiGouDTO = new NeiGouDTO();
                    $neiGouDTO->setGameArea($payOrder->game_area);
                    $neiGouDTO->setNumber($payOrder->number);
                    $neiGouDTO->setRoleId($payOrder->role_id);
                    $neiGouDTO->setOrderNo($payOrder->order_no);
                    $neiGouDTO->setGoodsId($payOrder->goods_id);
                    $neiGouDTO->setTypeValue($typeValue);
                    try {
                        $this->NeigouService->pushToServer($neiGouDTO);
                        $payOrder->updated_at = date("Y-m-d H:i:s");
                        $payOrder->push_status = 1;
                        $payOrder->save();
                    } catch (ServiceException $e) {
                        Log::error("push error: " . $e->getMessage());
                    }
                    return true;
                }
                return true;
            } else {
                return false;
            }

        } else {
            switch($code){
                case -1001: throw new ServiceException('参数错误');
                case -2013: throw new ServiceException('订单不存在');
                case -1009: throw new ServiceException('签名错误');
                case -5000: throw new ServiceException('系统错误');
            }
        }
    }

}
